package top.lyjwn.todo.aop.token;

import com.alibaba.fastjson2.JSONObject;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.method.HandlerMethod;
import top.lyjwn.todo.aop.token.redis.TokenRedis;
import top.lyjwn.todo.common.sm.SM2KeyPair;
import top.lyjwn.todo.common.sm.SM2Util;
import top.lyjwn.todo.common.template.R;
import top.lyjwn.todo.common.utils.JWTUtil;

import java.lang.reflect.Method;

/**
 * token过期时间
 *
 * @author luoyujie
 */
@Component
public class Token {

    @Autowired
    private TokenRedis tokenRedis;

    @Autowired
    private HttpServletRequest httpServletRequest;

    private final Logger log = LoggerFactory.getLogger("error");


    private JSONObject serialize(Login login) {
        //LoginData loginData = new LoginData(login.getAccount(), sm2Key.getPrivateKey(), login.getType(), login.getPlatform(), login.getOpenid(), login.getUnionid(), login.getUserId(), login.getLoginTime());
        JSONObject jsonObject = JSONObject.parseObject(JSONObject.toJSONString(login));
        jsonObject.put("userId", login.getUserId());
        return jsonObject;
    }

    public void updateTokenContent(Login login) {
        String token = httpServletRequest.getHeader("token");
        tokenRedis.set("token:" + token, serialize(login));
    }

    /**
     * 创建token
     *
     * @param login
     * @return
     */
    public String buildToken(Login login) {
        return buildToken(serialize(login));
    }


    public String buildToken(JSONObject jsonObject) {
        String platform = jsonObject.getString("platform");
        String id = jsonObject.getString("account");
        String userId = jsonObject.getString("yserId");
        StringBuffer token = new StringBuffer();
        StringBuffer redisKEY = new StringBuffer("token:");
        SM2KeyPair sm2Key = SM2Util.getSM2Key();
        if (!tokenRedis.IsJwt()) {
//            String timeMillis = Long.valueOf(System.currentTimeMillis()).toString();
//            StringBuffer tokenAppend = token.append(platform).append("_").append(id).append("_").append(userId).append("_");
//            String tokenAppendMd5 = DigestUtils.md5Hex(tokenAppend.toString());
//            int truncate = RandomValue.getRandomNumber(timeMillis.length());
//            StringBuilder timeMillisSub = new StringBuilder(timeMillis.substring(0, truncate));

            token = new StringBuffer(sm2Key.getPublicKey());
            redisKEY.append(token);
        } else {
            redisKEY.append(platform).append("_").append(id);
            token = new StringBuffer(JWTUtil.sign(redisKEY.toString(), userId));
        }

        if (tokenRedis.set(redisKEY.toString(), jsonObject, tokenRedis.getExpireTime())) {
            return token.toString();
        } else {
            return null;
        }
    }

    /**
     * 延期token
     *
     * @param token
     */
    public void postpone(String token) {
        if (token == null) {
            return;
        }
        tokenRedis.expire("token:" + token, tokenRedis.getExpire("token:" + token) + tokenRedis.getExpireTime());
    }

    /**
     * 刷新用户 token
     */
    public void refreshUserToken() {
        if (RequestContextHolder.getRequestAttributes() == null) {
            try {
                throw new Exception("未获得当前会话请求对象");
            } catch (Exception e) {
                e.printStackTrace();
            }
            return;
        }
        String token = httpServletRequest.getHeader("token");
        JSONObject loginByToken = getLoginByToken(JSONObject.class, token);
        tokenRedis.delete(token);
        tokenRedis.set("token:" + token, loginByToken);
    }

    /**
     * 用户退出登陆
     *
     * @param token
     */
    public void loginOff(String token) {
        if (token != null) {
            if (!tokenRedis.IsJwt()) {
                tokenRedis.delete("token:" + token);
            } else {
                String redisKEY = JWTUtil.getRedisKEY(token);
                tokenRedis.delete("token:" + redisKEY);
            }

        }
    }

    /**
     * 用户退出登陆
     */
    public void loginOff() {
        if (RequestContextHolder.getRequestAttributes() == null) {
            try {
                throw new Exception("未获得当前会话请求对象");
            } catch (Exception e) {
                e.printStackTrace();
            }
            return;
        }
        String token = httpServletRequest.getHeader("token");
        this.loginOff(token);
    }

    /**
     * 获取登录信息
     *
     * @param token
     * @return loginJson
     */
    public <T> T getLoginByToken(Class<T> clazz, String token) {
        JSONObject jsonObject = getLoginByToken(token);
        return jsonObject != null ? jsonObject.toJavaObject(clazz) : null;
    }

    public JSONObject getLoginByToken(String token) {
        if (!tokenRedis.IsJwt()) {
            return tokenRedis.get("token:" + token);
        } else {
            String redisKEY = JWTUtil.getRedisKEY(token);
            return tokenRedis.get("token:" + redisKEY);
        }

    }

    /**
     * 获取登录信息
     *
     * @return
     */
    public <T> T getLogin(Class<T> tClass) {
        JSONObject jsonObject = getLogin();
        return jsonObject != null ? jsonObject.toJavaObject(tClass) : null;
    }

    /**
     * 获取登录信息
     *
     * @return
     */
    public JSONObject getLogin() {
        if (RequestContextHolder.getRequestAttributes() == null) {
            return null;
        }
        String token = httpServletRequest.getHeader("token");
        if (token == null) {
            return null;
        }
        return getLoginByToken(token);
    }

    /**
     * 验证token
     *
     * @param token
     * @return
     */
    public boolean verify(String token) {
        JSONObject loginByToken = getLoginByToken(token);
        if (!tokenRedis.IsJwt()) {
            return loginByToken != null;
        } else {
            String platform = loginByToken.getString("platform");
            String id = loginByToken.getString("account");
            String vt = platform + "_" + id;
            return JWTUtil.verify(token, vt, loginByToken.getString("userId"));
        }
    }

    /**
     * 身份验证拦截器处理
     *
     * @param token
     * @return
     */
    public R authenticationInterceptor(String token, HttpServletResponse httpServletResponse,
                                       Object object) {
//		refreshUserToken(token);
        HandlerMethod handlerMethod = (HandlerMethod) object;
        Method method = handlerMethod.getMethod();
        // 返回的结果
        R r = new R();
        // 检查是否有passtoken注释，有则跳过认证
        if (method.isAnnotationPresent(ExemptToken.class)) {
            ExemptToken passToken = method.getAnnotation(ExemptToken.class);
            if (passToken.required()) {
                return r.ok("免token请求");
            }
        }
        // 如果没有免除token的请求，则进行验证
        if (token == null) {
            return r.error(401, "未发现token");
        }
        // 如果用户查找不到，则为假的token
        if (getLoginByToken(JSONObject.class, token) == null) {
            return r.error(401, "查询不到用户信息");
        }
        // 验证 token ,加密的正确性
        if (verify(token)) {

            return r.ok("token验证成功");
        } else {
            log.error("token验证失败" + token);
            return r.error(401, "token验证失败");
        }

    }


    public boolean IsJwt() {
        return this.tokenRedis.IsJwt();
    }


}
